﻿using System;
using System.Collections.Generic;
using System.Text;
using IAnalyze;
using System.Threading;
using System.Drawing;
using System.Diagnostics;

namespace SmokeFireAnalyze
{
    class SmokeFireAnalyzeStrategy : IAnalyzeStrategy
    {
        #region 私有变量
        int width = 352, height = 288;      //识别帧宽、高
        readonly int SkipCount = 5;         //跳帧数：表示识别帧之间的间隔帧数
        readonly int AnalyzeCount = 200;    //总识别帧数
        readonly int AlarmThreshold = 1;    //报警阈值：当报警帧积累到一定数量时向外部通道报警
        int AnalyzeIndex = 0;               //识别帧索引号
        int AlarmCount = 0;                 //报警帧数量

        bool isAnalyzing = false;
        int tick = 0;

        AutoResetEvent startLock = new AutoResetEvent(false);        //同步开启锁
        AutoResetEvent stopLock = new AutoResetEvent(false);         //同步停止锁
        //报警帧缓存
        List<EventArgsAnalyzeAlarm> cacheAlarms = new List<EventArgsAnalyzeAlarm>();

        EventArgsAnalyzeBegin analyzeBegin = null;
        #endregion

        #region IAnalyzeStrategy 成员

        public event EventHandler<EventArgsAnalyzeBegin> AnalyzeBegin;

        public event EventHandler<EventArgsAnalyzeAlarm> AnalyzeAlarm;

        public event EventHandler<EventArgsAnalyzeEnd> AnalyzeEnd;

        public int FrameSkipRate
        {
            get { return this.SkipCount; }
        }

        public int FrameAnalyzeCount
        {
            get { return this.AnalyzeCount; }
        }

        public int FrameAlarmThreshold
        {
            get { return this.AlarmThreshold; }
        }

        public int Width
        {
            get { return this.width; }
        }

        public int Height
        {
            get { return this.height; }
        }

        public void InputVideoStream(IntPtr stream, int width, int height)
        {
            if (!isAnalyzing) return;

            if (++this.tick % this.SkipCount != 0) return;
            else tick = 0;

            this.width = width;
            this.height = height;
            Bitmap frameAlarm = new Bitmap(this.width, this.height);

            if (this.AnalyzeIndex > this.AnalyzeCount)
            {//识别结束
                this.isAnalyzing = false;
                this.AnalyzeIndex = 0;
                if (this.cacheAlarms.Count < this.AlarmThreshold)
                {
                    //释放缓存
                    foreach (EventArgsAnalyzeAlarm alarmInfo in this.cacheAlarms)
                    {
                        alarmInfo.AlarmFrame.Dispose();
                    }
                    this.cacheAlarms.Clear();
                }

                //向外部提示一轮报警结束
                if (this.AnalyzeEnd != null && this.analyzeBegin != null)
                    this.AnalyzeEnd(this, new EventArgsAnalyzeEnd(analyzeBegin.GroupID));

                this.startLock.Set();
                this.stopLock.Set();
            }
            else
            {
                if (this.AnalyzeIndex == 0)
                {//开始识别
                    this.analyzeBegin = new EventArgsAnalyzeBegin(this.AnalyzeCount);

                    if (this.AnalyzeBegin != null)
                        this.AnalyzeBegin(this, this.analyzeBegin);
                }

                this.AnalyzeIndex++;

                //将YV12转成灰度图像
                ImageProcessing.YV12.DecodeYV12ToGrey(stream, frameAlarm);
                Rectangle[] region;
                int[] regionType;

                Stopwatch SW = Stopwatch.StartNew();
                //识别
                if (this.analyze.Analyze(frameAlarm, out region, out regionType))
                {//报警
                    SW.Stop();
                    lock (this)
                    {
                        EventArgsAnalyzeAlarm alarmInfo = new EventArgsAnalyzeAlarm(
                                    this.analyzeBegin.GroupID,
                                    this.AnalyzeIndex,
                                    frameAlarm,
                                    DateTime.Now,
                                    region,
                                    regionType);

                        if (AlarmCount < this.AlarmThreshold)
                        {//未达到报警阈值，缓存报警信息
                            this.cacheAlarms.Add(alarmInfo);
                        }
                        else if (AlarmCount == this.AlarmThreshold)
                        {//达到报警阈值，清空缓存
                            foreach (EventArgsAnalyzeAlarm alarm in this.cacheAlarms)
                            {
                                if (this.AnalyzeAlarm != null)
                                    this.AnalyzeAlarm(this, alarm);
                            }
                            this.cacheAlarms.Clear();
                        }
                        else
                        {//超过报警阈值，直接报警
                            if (this.AnalyzeAlarm != null)
                                this.AnalyzeAlarm(this, alarmInfo);
                        }

                        this.AlarmCount++;
                    }
                }
                else
                {
                    SW.Stop();
                    frameAlarm.Dispose();
                }
            }

        }

        IAnalyze.IAnalyze analyze;
        IAnalyze.IAnalyze IAnalyzeStrategy.Analyze
        {
            set { analyze = value; }
        }

        public void SyncStartAnalyzeStrategy()
        {
            if (this.analyze == null || this.isAnalyzing) return;

            this.isAnalyzing = true;
            this.analyze.Reset();   //重置识别类
            startLock.WaitOne();
            startLock.Reset();
        }

        public void SyncStopAnalyzeStrategy(int millisecondsTimeout)
        {
            if (this.analyze == null || !this.isAnalyzing) return;
            this.AnalyzeIndex = this.AnalyzeCount + 1;    //设置识别结束条件
            //stopLock.WaitOne(millisecondsTimeout);         //等待识别结束
            stopLock.WaitOne();         //等待识别结束
            stopLock.Reset();
        }

        #endregion

    }
}
